#pragma once

#include "TreeNode.h"
#include "PKB.h"

class QueryExpressionParser {
	private:
		PKB *mPkb;
		std::map<std::string, int> mMapOfMathSymbols; // contains the math symbols and their corresponding precedence
		std::map<std::string, TreeNodeType> mMapOfMathOperators; // contains the math operators and their corresponding TreeNodeType

		// Initializes the member variable mVectorOfMathSymbols
		void initializeMapOfMathSymbols();
		// Recursively converts an expression to a tree.
		TreeNode* convertExpressionToTreeRecursively(std::vector<std::string> exprTokens, 
													int *numOfOpenBrackets, int *currentPosition, int endPosition);
		// Adds one space to the expr before and after math symbols and returns the resulting string.
		std::string addSpacesToExpressionBeforeAndAfterMathSymbols(std::string expr);
		// Tokenizes the expr by whitespace and returns the tokens as a vector of strings.
		std::vector<std::string> tokenizeByWhitespace(std::string expr);
		// Adds bracket tokens to the given math expression tokens and returns the new tokens.
		// E.g. For expr 1 + 2 + 3 * (x + y) * 2, 
		// the original exprTokens will be [1,+,2,+,3,*,(,x,+,y,),*,2],
		// but after adding brackets according to precedence,
		// the returned tokens will represent 1+2+(3*(x+y))*2
		std::vector<std::string> addBracketsAccordingToPrecedence(std::vector<std::string> exprTokens);
		// Recursive helper function for the addBracketsAccordingToPrecedence function, called everytime an open bracket is met.
		// Returns an int denoting the position where it stopped checking.
		int addBracketsAccordingToPrecedenceRecursiveHelper(std::vector<std::string> *exprTokens, unsigned int startPos, unsigned int addOpenBracketPosition);
		// Compares two math operators to compare their precedence level.
		// Returns operator1 precedence - oprator2 precendence as defined in the mMapOfMathSymbols,
		// and if any of the operators defined does not exist in the map, then returns 0.
		int compareMathOperators(std::string operator1, std::string operator2);
		// Returns the math operator tree node type (e.g. AST_MINUS) based on the math operator that is
		// represented by token.
		// Returns AST_INVALID_TYPE if token is not a representation of a math operator as defined in the mMapOfMathOperators.
		TreeNodeType getMathOperatorTNodeType(std::string token); 
		// Returns true if s is a math symbol as specified in mMapOfMathSymbols,
		// false otherwise.
		bool isMathSymbol(std::string s);
		// Returns true if c is a math symbol as specified in mMapOfMathSymbols,
		// false otherwise.
		bool isMathSymbol(char c);
		// Returns true if s is a math operator as specified in mMapOfMathOperators,
		// false otherwise.
		bool isMathOperator(std::string s);
		// Returns true if c is a math operator as specified in mMapOfMathOperators,
		// false otherwise.
		bool isMathOperator(char c);
		// Returns true if the startingToken is valid for a mathematical expression in SPA.
		// e.g. "a" or "myVariable" or "1" or "(" are valid as long as "a" and "myVariable" exist in the PKB as variables.
		bool isValidStartingToken(std::string startingToken);
		// Returns true if the token is "(", false otherwise.
		bool isOpenBracket(std::string token);
		// Returns true if the token is ")", false otherwise.
		bool isCloseBracket(std::string token);
		// Returns true if the token is integer-parseable, false otherwise.
		bool isConstantInteger(std::string token);
		// Returns true if the token is a valid variable name, false otherwise.
		// A valid variable name starts with an alphabet from a-z or A-Z,
		// and can be followed by more alphabets or digits (0-9)
		bool isValidVariableName(std::string token);
		// Returns true if c is an alphabet a-z or A-Z, false otherwise.
		bool isAlphabet(char c);
		// Returns true if c is a digit from 0-9, false otherwise.
		bool isDigit(char c);
		// Gets the variable index of the token from the mPKB.
		// Note: -1 is returned if the token does not exist in the mPKB's varTable.
		int getVariableIndexFromPKB(std::string token);
		// Returns a string representing the math operator of the given nodeType.
		// Returns an empty "" string if nodeType does not represent any math operator.
		// e.g. nodeType AST_MINUS returns "-" as defined in the mMapOfMathOperators.
		std::string translateTreeNodeTypeToMathOperator(TreeNodeType nodeType);
		std::string convertStringVectorToString(std::vector<std::string> stringVector);
	public:
		/**
		 * Builds the QueryExpressionParser with the proper PKB to query from when needing to input values of 
		 * variable index into the tree nodes which it builds.
		 */
		QueryExpressionParser(PKB *pkb);
		~QueryExpressionParser(void);
		/**
		 * Takes a mathematical expression and converts it into a tree.
		 * Returns the pointer to the root node of that tree.
		 * Currently valid expressions:
		 * "x", "1", "1+x", "(x+y)", "x*(y-z)", etc
		 * If the expr is an invalid expr, a NULL pointer is returned.
		 */
		TreeNode* convertExpressionToTree(std::string expr);
};

